using System;
using System.Collections.Generic;
using System.Text;
using RapidHDL;

namespace NegBinary
{
    class NegBinary2Comp: TruthTableComponent
    {
        public NodeVector I_INPUT;
        public NodeVector I_TO_NEGA;
        public NodeVector O_RESULT;

        int iInputWidth;
        long lLowRangeNega = 0;
        long lHighRangeNega = 0;
        long lLowRangeBinary = 0;
        long lHighRangeBinary = 0;

        public NegBinary2Comp(Component poParentComponent, string psName, int piInputWidth)
            : base(poParentComponent, psName)
        {
            iInputWidth = piInputWidth;
            this.GetTruthTable("NegaBinary2Comp", iInputWidth + 1, iInputWidth + 2);
            I_INPUT = this.CreateNodeVector("I_INPUT", iInputWidth, NodeFlowType.Sink);
            I_TO_NEGA = this.CreateNodeVector("I_TO_NEGA", 1, NodeFlowType.Sink);
            O_RESULT = this.CreateNodeVector("O_RESULT", iInputWidth + 2, NodeFlowType.Source);
        }

        protected override void GenerateTruthTable()
        {
            long lTest = 0;
            bool bOverflow = false;
            
            while (!bOverflow)
            {
                try
                {
                    string sTest = Convert.LongToNegBinary(lTest + 1, iInputWidth);
                    lTest = lTest + 1;
                }
                catch
                {
                    bOverflow = true;
                }                
            }
            lHighRangeNega = lTest;

            bOverflow = false;
            while (!bOverflow)
            {
                try
                {
                    string sTest = Convert.LongToNegBinary(lTest - 1, iInputWidth);
                    lTest = lTest  - 1;
                }
                catch
                {
                    bOverflow = true;
                }
            }
            lLowRangeNega = lTest;

            lTest = 0;
            string sBinary = Conversion.SignedLongToBinaryString(lTest,iInputWidth);
            while (lTest == Conversion.StringBinaryToSignedLong(sBinary))
            {
                lTest++;
                sBinary = Conversion.SignedLongToBinaryString(lTest, iInputWidth);
            }
            lHighRangeBinary = lTest - 1;

            lTest = 0;
            sBinary = Conversion.SignedLongToBinaryString(lTest, iInputWidth);
            while (lTest == Conversion.StringBinaryToSignedLong(sBinary))
            {
                lTest--;
                sBinary = Conversion.SignedLongToBinaryString(lTest, iInputWidth);
            }
            lLowRangeBinary = lTest + 1;

            this.TruthTable.AddTableEntry("default", new string('X',iInputWidth + 2));

            long lStart = lLowRangeNega;
            long lEnd = lHighRangeNega;

            if (lStart > lLowRangeBinary)
                lStart = lLowRangeBinary;
            if (lEnd < lHighRangeBinary)
                lEnd = lHighRangeBinary;

            Console.WriteLine("Nega - " + lLowRangeNega + " " + lHighRangeNega);
            Console.WriteLine("Binary - " + lLowRangeBinary + " " + lHighRangeBinary);

            for(long lConvert = lStart; lConvert <= lEnd; lConvert++)
            {
                string sResult = "";
                string sInput = "";

                Console.WriteLine(lConvert.ToString() + " - " + Convert.LongToNegBinary(lConvert, iInputWidth + 2) + " , " + Conversion.SignedLongToBinaryString(lConvert, iInputWidth + 2));

                // negabinary -> binary conversion first
                if (lConvert >= lLowRangeNega && lConvert <= lHighRangeNega)
                {
                    sInput = Convert.LongToNegBinary(lConvert, iInputWidth) + "0";
                    sResult = Conversion.SignedLongToBinaryString(lConvert, iInputWidth + 2);
                    this.TruthTable.AddTableEntry(sInput, sResult);
                }


                // binary -> negabinary conversion
                if (lConvert >= lLowRangeBinary && lConvert <= lHighRangeBinary)
                {
                    sInput = Conversion.SignedLongToBinaryString(lConvert, iInputWidth) + "1";
                    sResult = Convert.LongToNegBinary(lConvert, iInputWidth + 2);
                    this.TruthTable.AddTableEntry(sInput, sResult);
                }
            }
        }

        public override bool TransformStructureToVerilog()
        {
            WriteVerilogLookupTable();
            return true;
        }
    }
}
